package ${filePackageName};

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import ${commonVoPackage}.FileInfoVo;
import ${enumsPackage}.EnumCode;
import ${exceptionPackage}.BusinessException;
import ${utilsPackage}.MessageUtils;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.http.MediaType;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.servlet.HandlerMapping;
import cn.hutool.core.codec.Base64Encoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.Date;

/**
 * 文件操作工具类
 * @author ${projectAuthor}
 * @version 1.0
 * @date ${nowDate}
 */
public class FileUtil {

    /**
     * 获取资源文件流
     * @param filePath
     * @return
     */
    public InputStream getResourceInputStream(String filePath){
        InputStream inputStream = this.getClass().getResourceAsStream(filePath);
        if(inputStream==null){
            throw new BusinessException(EnumCode.FILE_NOT_EXIST);
        }
        return inputStream;
    }


    /**
     * 文件预览写文件
     * @param file
     * @param range
     * @param response
     */
    public static void writeFile(File file, String range, HttpServletResponse response){

        RandomAccessFile randomFile = null;
        ServletOutputStream out = null;
        try {
            randomFile = new RandomAccessFile(file, "r");//只读模式
            long contentLength = randomFile.length();
            int start = 0, end = 0;
            if (range != null && range.startsWith("bytes=")) {
                String[] values = range.split("=")[1].split("-");
                start = Integer.parseInt(values[0]);
                if (values.length > 1) {
                    end = Integer.parseInt(values[1]);
                }
            }
            int requestSize = 0;
            if (end != 0 && end > start) {
                requestSize = end - start + 1;
            } else {
                requestSize = Integer.MAX_VALUE;
            }

            String contentType = Files.probeContentType(Paths.get(file.getAbsolutePath()));
            response.setHeader("Content-Type", contentType);
            //response.setContentType("video/mp4");
            response.setHeader("Accept-Ranges", "bytes");
            response.setHeader("ETag", file.getName());
            response.setHeader("Last-Modified", new Date().toString());
            //第一次请求只返回content length来让客户端请求多次实际数据
            if (range == null) {
                response.setHeader("Content-length", contentLength + "");
            } else {
                //以后的多次以断点续传的方式来返回视频数据
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206
                long requestStart = 0, requestEnd = 0;
                String[] ranges = range.split("=");
                if (ranges.length > 1) {
                    String[] rangeDatas = ranges[1].split("-");
                    requestStart = Integer.parseInt(rangeDatas[0]);
                    if (rangeDatas.length > 1) {
                        requestEnd = Integer.parseInt(rangeDatas[1]);
                    }
                }
                long length = 0;
                if (requestEnd > 0) {
                    length = requestEnd - requestStart + 1;
                    response.setHeader("Content-length", "" + length);
                    response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);
                } else {
                    length = contentLength - requestStart;
                    response.setHeader("Content-length", "" + length);
                    response.setHeader("Content-Range", "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength);
                }
            }
            out = response.getOutputStream();
            int needSize = requestSize;
            randomFile.seek(start);
            while (needSize > 0) {
                byte[] buffer = new byte[1024 * 1024];
                int len = randomFile.read(buffer);
                if (needSize < buffer.length) {
                    out.write(buffer, 0, needSize);
                } else {
                    out.write(buffer, 0, len);
                    if (len < buffer.length) {
                        break;
                    }
                }
                needSize -= buffer.length;
            }
        } catch (IOException e) {
            output(response, MessageUtils.get(EnumCode.PREVIEW_FILE_EXCEPTION), MediaType.TEXT_HTML_VALUE);
        } finally {
            try {
                if (randomFile != null) {
                    randomFile.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @param response
     * @param data
     * @param contentType json格式： application/json;charset=UTF-8
     *                    html：text/html;charset=UTF-8
     *                    MediaType.TEXT_HTML_VALUE
     *                    MediaType.APPLICATION_JSON_VALUE
     */
    public static void output(HttpServletResponse response, String data, String contentType) {
        try {
            response.setCharacterEncoding("utf-8");
            response.setContentType(contentType);
            PrintWriter out = response.getWriter();
            out.print(data);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String extractPathFromPattern(final HttpServletRequest request) {
        String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
        String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
    }

    /**
     * 上传文件
     *
     * @param base64Str
     * @param folder
     * @throws IOException
     */
    public static FileInfoVo uploadFile(String base64Str, String folder, String rootPath) throws IOException {
        if(StrUtil.isBlank(base64Str)){
            throw new BusinessException(EnumCode.PARAMS_NOT_EMPTY, "base64Str字符串不能为空");
        }
        String replaceStr = "base64";
        if(base64Str.indexOf(replaceStr)!=-1){
            base64Str = base64Str.substring(base64Str.indexOf(replaceStr)+replaceStr.length()+1);
        }

        folder = StrUtil.isNotBlank(folder)?folder: "other";
        cn.hutool.core.io.FileUtil.mkdir(rootPath + folder);

        String suffix = "png";
        String myFileName = UUID.fastUUID().toString(true)+"."+suffix;

        FileInfoVo fileInfoVo = new FileInfoVo();
        fileInfoVo.setFileName(myFileName);

        String realFileName = folder + File.separator + myFileName ;
        fileInfoVo.setFilePath(realFileName.replaceAll("\\\\", "/"));
        fileInfoVo.setSuffix(suffix);

        String filePath = rootPath + realFileName;

        byte[] b = Base64.getDecoder().decode(base64Str);
        for (int i = 0; i < b.length; ++i) {
            if (b[i] < 0) {
                // 调整异常数据
                b[i] += 256;
            }
        }
        // 生成图片路径和文件名
        FileOutputStream out = new FileOutputStream(new File(filePath));
        out.write(b);
        out.flush();
        out.close();

        File file = new File(filePath);
        fileInfoVo.setFileSize(file.length());
        fileInfoVo.setLinkType(folder);
        return fileInfoVo;
    }

    public static String getBase64Str(InputStream inputStream) {
        if (inputStream != null) {
            byte[] data = null;
            try {
                data = new byte[inputStream.available()];
                inputStream.read(data);
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            Base64Encoder encoder = new Base64Encoder();
            return encoder.encode(data);
        }
        return null;
    }

    public static MultipartFile getMultipartFile(String filePath) throws IOException {
        FileItem fileItem = createFileItem(new File(filePath));
        return new CommonsMultipartFile(fileItem);
    }

    public static MultipartFile getMultipartFile(File file) throws IOException {
        FileItem fileItem = createFileItem(file);
        return new CommonsMultipartFile(fileItem);
    }

    public static FileItem createFileItem(File file) throws IOException {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem(file.getName(), "text/plain", true, file.getName());
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        FileInputStream fis = new FileInputStream(file);
        OutputStream os = item.getOutputStream();
        while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        fis.close();
        return item;
    }

    /**
     * 压缩图片
     *
     * @param file
     * @param formatName
     * @param outPath
     * @throws IOException
     */
    public static void createThumbnail(File file, String formatName, String outPath) throws IOException {
        cn.hutool.core.io.FileUtil.mkParentDirs(outPath);
        long size = file.length();
        if (size > 1024 * 1024) {
            double scale = (1024 * 1024) * 1.0 / size;
            FileInputStream fis = new FileInputStream(file);
            Thumbnails.of(fis).scale(scale).outputFormat(formatName).toFile(outPath);
            if(fis!=null){
                fis.close();
            }
        }else {
            cn.hutool.core.io.FileUtil.copy(file,new File(outPath),true);
        }
    }

    public static void main(String[] args) {
        String filePath = "C:\\Users\\User\\Desktop\\dslogo.png";
        File file = new File(filePath);
        if (!file.exists()) {
            throw new BusinessException(EnumCode.FILE_NOT_EXIST);
        }
        String fileName = file.getName();
        String suffix = "";
        if(StrUtil.isNotBlank(fileName)
                && fileName.indexOf(".")!=-1){
            suffix = fileName.substring(fileName.lastIndexOf(".")+1);
        }

        //压缩
        String outPath = filePath.substring(0,filePath.lastIndexOf("."))+"_thumbnail."+suffix;

        System.out.println(outPath);
    }
}
